package com.hexinfo.dmpro.sparing.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileAppender;
import cn.hutool.core.util.StrUtil;
import com.hexinfo.dmpro.common.model.MessageCenter;
import com.hexinfo.dmpro.common.service.MessageCenterService;
import com.hexinfo.dmpro.common.utils.ScanCommonConstants;
import com.hexinfo.dmpro.sparing.dao.SyncRuleConfMapper;
import com.hexinfo.dmpro.sparing.dao.TimeFieldMatchingMapper;
import com.hexinfo.dmpro.sparing.dto.DropDateDataDTO;
import com.hexinfo.dmpro.sparing.model.TimeFieldMatching;
import com.hexinfo.dmpro.sparing.service.AsyncDropDataService;
import com.hexinfo.dmpro.sparing.service.DropDateDataService;
import com.hexinfo.dmpro.sparing.util.Logger;
import com.xqfunds.job.core.log.XxlJobLogger;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.io.File;
import java.sql.Connection;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * 删除两年前日期分区数据
 */
@Service
@Slf4j
public class DropDateDataServiceImpl implements DropDateDataService {

    @Value("${heatBackup.dropDateDataPath}")
    private String logPath;

    @Autowired
    @Qualifier("connPoolImpalaTarget")
    private DataSource connPoolImpalaTarget;

    @Autowired
    private MessageCenterService messageCenterService;
    @Autowired
    private AsyncDropDataService asyncDropDataService;
    @Autowired
    private SyncRuleConfMapper syncRuleConfMapper;
    @Autowired
    private TimeFieldMatchingMapper timeFieldMatchingMapper;

    /**
     * 删除两年前日期分区数据
     */
    @Override
    public boolean dropDateData(String source) {
        //获取日志路径
        String logFilePath = path(source);
        FileAppender heatlog = new FileAppender(new File(logFilePath), 1000, true);
        heatlog.append(logTime("【删除两年前日期分区数据开始】"));
//        Logger.log("【删除两年前日期分区数据开始】");

        //添加进消息中心
        MessageCenter messageCenter = getMessageCenter(ScanCommonConstants.ClusterName.JXZ.value, logFilePath);
        messageCenterService.save(messageCenter);
        String id = messageCenter.getId();   //消息中心id

        //按源值获取底下所有表信息
        List<DropDateDataDTO> dropDateDataDTOs = getDropDateDataDTOs(source);
        heatlog.append(logTime("【表数量：】"+dropDateDataDTOs.size()));
//        Logger.log("【表数量：】"+dropDateDataDTOs.size());

        //获取拼接后删除两年前日期分区数据的dropSql
        List<String> dropSqlList = getDropSqlList(dropDateDataDTOs, heatlog);
        int size = dropSqlList.size();
        heatlog.append(logTime("【dropSQL数量：】"+size));
//        Logger.log("【dropSQL数量：】"+size);
        for (String s : dropSqlList) {
            heatlog.append(logTime("【dropSQL：】"+s));
        }
        heatlog.flush();

//        //给一个任务执行情况初始状态
//        asyncDropDataService.updateTaskState(source,true);
//        //结束状态，给一个初始值
//        asyncDropDataService.updateEndFlag(source,false);
//        //----------------------------线程池异步删除数据---------------
//        for (String dropSql : dropSqlList) {
//            asyncDropDataService.execShell(dropSql,source,size,heatlog);
//        }
//        //----------------------------循环判断删除任务是否全部执行完---------------
//        //循环判断这个源的热备是否全部结束
//        while (!asyncDropDataService.getEndFlag(source)){
//            try {
//                Thread.sleep(5000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//        //删除源key
//        asyncDropDataService.deleteEndFlag(source);
//
//        //----------------------------连接万国impala执行invalidate每个表---------------
//        heatlog.append(logTime("----------连接万国impala执行invalidate每个表----------"));
//        XxlJobLogger.log("----------连接万国impala执行invalidate每个表----------");
//        boolean state = invalidateTable(dropDateDataDTOs,heatlog);
//        heatlog.append(logTime("【删除两年前日期分区数据结束】"));
//        XxlJobLogger.log("【删除两年前日期分区数据结束】");
//        heatlog.flush();
//
//        //----------------------------判断删除任务执行是否异常---------------
//        //消息中心状态修改
//        if(asyncDropDataService.getTaskState(source) && state){
//            messageCenterChange(id,ScanCommonConstants.ClusterName.YWC.value);
//            asyncDropDataService.deleteTaskState(source);  //删除key
//            return true;
//        }else {
//            messageCenterChange(id,ScanCommonConstants.ClusterName.YC.value);
//            asyncDropDataService.deleteTaskState(source);   //删除key
//            return false;
//        }
        return true;
    }

    /**
     * invalidate每张表
     */
    private boolean invalidateTable(List<DropDateDataDTO> dropDateDataDTOs,FileAppender heatlog) {
        boolean state = true;
        try {
            Connection impalaTarConn = connPoolImpalaTarget.getConnection();
            @Cleanup
            Statement st = impalaTarConn.createStatement();
            String invalidateSql = "invalidate metadata {dbTbName}";
            int j = 0;
            for (DropDateDataDTO dropDateDataDTO : dropDateDataDTOs) {
                j++;
                String replace = "";
                try{
                    replace = invalidateSql.replace("{dbTbName}", dropDateDataDTO.getDbTbName());
                    int i = st.executeUpdate(replace);
                    heatlog.append(logTime("（"+j+"）执行invalidate的："+replace+"--执行结果："+i));
//                    Logger.log("（"+j+"）执行invalidate的："+replace+"--执行结果："+i);
                }catch (Exception e){
                    state = false;
                    log.error("（"+j+"）执行invalidate的："+replace+"【异常】："+e);
                    heatlog.append(logTime("（"+j+"）执行invalidate的："+replace+"【异常】："+e));
//                    Logger.log("（"+j+"）执行invalidate的："+replace+"【异常】："+e);
                }
            }
        } catch (Exception e) {
            state = false;
            log.error("【执行invalidate获取连接池连接异常】："+e);
            heatlog.append(logTime("【执行invalidate获取连接池连接异常】："+e));
//            Logger.log("【执行invalidate获取连接池连接异常】："+e);
        }
        return state;
    }

    /**
     * drop语句拼接
     */
    private List<String> getDropSqlList(List<DropDateDataDTO> dropDateDataDTOs,FileAppender heatlog) {
        List<String> dropSqls = new ArrayList<String>();
        String dropSql = "alter table {dbTbName} drop if exists partition (cast({souColName} as string) = '{souValue}' , cast({dateColName} as decimal(8,0)) < {dateValue})";
        String dropSqlNotSou = "alter table {dbTbName} drop if exists partition (cast({dateColName} as decimal(8,0)) < {dateValue})";
        // 获取两年前的日期
        DateTime offset = DateUtil.offset(DateUtil.date(), DateField.YEAR, -2);
        heatlog.append(logTime("获取两年前的日期："+offset));
        //heatlog.append(logTime("【获取删除两年前日期分区数据sql：】"));
        for (DropDateDataDTO dropDateDataDTO : dropDateDataDTOs) {
            String twoDate = getTwoDate(dropDateDataDTO.getDateValue(),offset);
            //按照类型生成不同的dropSql
            if (dropDateDataDTO.getSqlType().equals("1")){
                String replace = dropSql
                        .replace("{dbTbName}", dropDateDataDTO.getDbTbName())
                        .replace("{souColName}",dropDateDataDTO.getSouColName())
                        .replace("{souValue}",dropDateDataDTO.getSouValue())
                        .replace("{dateColName}",dropDateDataDTO.getDateColName())
                        .replace("{dateValue}",twoDate);
                dropSqls.add(replace);
            }else if (dropDateDataDTO.getSqlType().equals("2")){
                String replace = dropSqlNotSou
                        .replace("{dbTbName}", dropDateDataDTO.getDbTbName())
                        .replace("{dateColName}",dropDateDataDTO.getDateColName())
                        .replace("{dateValue}",twoDate);
                dropSqls.add(replace);
            }
            //heatlog.append(logTime(replace));
        }
        return dropSqls;
    }

    /**
     * 通过源值获取dropSql表集合
     */
    private List<DropDateDataDTO> getDropDateDataDTOs(String source) {
        //查询规则-元数据视图表获取数据
        List<DropDateDataDTO> dropDateDataDTOs = syncRuleConfMapper.getDropDateDataDTOs(source);
        //日期分区格式表中所有日期分区字段名
        List<String> dateTypes = timeFieldMatchingMapper.getDateType();
        //整理实体类
        List<DropDateDataDTO> dropDateDataDTOS = new ArrayList<DropDateDataDTO>();
        for (DropDateDataDTO dropDateDataDTO : dropDateDataDTOs) {
            //日期分区字段在源分区字段前
            if (dateTypes.contains(dropDateDataDTO.getSouColName())){
                String sqlType = "1";
                //没有源分区字段
                if (StrUtil.isBlank(dropDateDataDTO.getDateColName())){
                    sqlType = "2";
                //两个分区字段都是在日期分区表中的日期分区字段
                }else if (dateTypes.contains(dropDateDataDTO.getDateColName())){
                    sqlType = "2";
                }
                DropDateDataDTO dropDateData = new DropDateDataDTO(
                        dropDateDataDTO.getDbName(),
                        dropDateDataDTO.getTbName(),
                        dropDateDataDTO.getDateColName(),
                        dropDateDataDTO.getDateValue(),
                        dropDateDataDTO.getSouColName(),
                        dropDateDataDTO.getSouValue(),
                        sqlType
                );
                dropDateDataDTOS.add(dropDateData);
            //源分区字段在日期分区字段前
            }else {
                dropDateDataDTOS.add(dropDateDataDTO);
            }
        }
        return dropDateDataDTOS;
    }

    /**
     * 消息中心
     */
    private MessageCenter getMessageCenter(String state,String logFilePath) {
        MessageCenter messageCenter = new MessageCenter();
        messageCenter.setMenu(ScanCommonConstants.ClusterName.QCSJ.value);
        messageCenter.setOperator("admin");
        messageCenter.setDataType(state);
        messageCenter.setMessageSubject(ScanCommonConstants.ClusterName.QCRQSJ.value);
        messageCenter.setMessageWeight(ScanCommonConstants.ClusterName.ONE.value);
        messageCenter.setLogPath(logFilePath);
        return messageCenter;
    }

    /**
     * 修改这一次消息中心状态为已完成
     * @return
     */
    private void messageCenterChange(String id,String state) {
        MessageCenter mess = messageCenterService.getById(id);
        mess.setDataType(state);
        messageCenterService.updateById(mess);
    }

    /**
     * 按照日期格式获取两年前日期
     */
    private String getTwoDate(String dateValue,DateTime offset) {
        String twoDate = "";
        if (dateValue.length() == 8){
            twoDate = DateUtil.format(offset, "yyyyMMdd");
        }else if (dateValue.length() == 6){
            twoDate = DateUtil.format(offset, "yyyyMM");
        }else if (dateValue.length() == 4){
            twoDate = DateUtil.format(offset, "yyyy");
        }
        return twoDate;
    }

    /**
     *获取当天日期文件夹路径
     */
    public String path(String sounName) {
        return logPath.replace("{date}", DateUtil.format(DateUtil.date(), "yyyyMMdd"))
                + sounName + ".txt";
    }

    /**
     * 日志加日期时间
     */
    private String logTime(String str) {
        return "["+DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")+"]" +str;
    }

}
